using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Web.UI;
using System.Web.UI.WebControls;
using Sedna.Core.Controller;
using Sedna.Core.Controller.Configurations;
using Sedna.Core.Controls.Enum;
using Sedna.Core.Controls.Support;
using Sedna.Core.Controls.Support.Javascript;
using Sedna.Core.Tiles.Contents;
using DataBinder = Sedna.Core.DataBinding.DataBinder;

namespace Sedna.Core.Controls
{
    [ValidationProperty("SelectedCount")]
    public class CheckBoxList : BaseControl, IContent, IListControl, IConfigurationAware, IClientScriptingControl, IControlDataLoadAware, IControlBindingAware
    {
        #region Fields

        private System.Web.UI.WebControls.CheckBoxList checkListBox = new System.Web.UI.WebControls.CheckBoxList();

        private IMultiSelectListController controller;

        private System.Web.UI.WebControls.Label selectAll = new System.Web.UI.WebControls.Label();
        private System.Web.UI.WebControls.Label unselectAll = new System.Web.UI.WebControls.Label();
        

        #endregion

        # region Construcotrs

        public CheckBoxList()
            : base()
        {
        }

        public CheckBoxList(IConfiguration configuration)
            : base(configuration)
        {
            BuildFromConfiguration();
        }

        # endregion

        # region Properties

        public override string ID
        {
            get { return base.ID; }
            set
            {
                base.ID = value;
                checkListBox.ID = value + "_clb";
            }
        }

        public IMultiSelectListController Controller
        {
            get { return controller; }
            set
            {
                if (value == null && controller != null)
                {
                    controller.OnControlChanged -= new ControlHandler(Controller_OnControlChanged);

                    if (controller.Control == this)
                        controller.Control = null;
                }
                
                controller = value;

                if (controller != null)
                {
                    controller.Control = this;
                    controller.OnControlChanged += new ControlHandler(Controller_OnControlChanged);
                }
            }
        }

        protected new ICheckBoxListConfiguration Configuration
        {
            get { return configuration as ICheckBoxListConfiguration; }
        }

        public object DataSource
        {
            get { return checkListBox.DataSource; }
            set { checkListBox.DataSource = value; }
        }

        public string DataTextField
        {
            get { return checkListBox.DataTextField; }
            set { checkListBox.DataTextField = value; }
        }

        public string DataValueField
        {
            get { return checkListBox.DataValueField; }
            set { checkListBox.DataValueField = value; }
        }
        
        public int SelectedIndex
        {
            get { return checkListBox.SelectedIndex; }
            set { checkListBox.SelectedIndex = value; }
        }
        
        public string SelectedValue
        {
            get { return checkListBox.SelectedValue; }            
        }

        public IList<String> SelectedValues
        {
            get
            {
                IList<String> list = new List<String>();

                foreach (ListItem item in SelectedItems)
                {
                    list.Add(item.Value);
                }

                return list;
            }
        }


        public ListItemCollection Items
        {
            get { return checkListBox.Items; }
        }

        public ListItem SelectedItem
        {
            get { return checkListBox.SelectedItem; }            
        }

        public IList<ListItem> SelectedItems
        {
            get
            {
                IList<ListItem> list = new List<ListItem>();

                foreach (ListItem item in Items)
                {
                    if (item.Selected)
                        list.Add(item);
                }
                
                return list;
            }
        }

        public string SelectedText
        {
            get { return (SelectedItem == null) ? null : SelectedItem.Text; }
        }
        
        public int SelectedCount
        {
            get { return SelectedItems.Count; }
        }

        # endregion
        
        public void UnselectAll()
        {
            foreach (ListItem item in SelectedItems)
            {
                item.Selected = false;
            }
        }

        # region Events

        public event BindingHandler BeforeBinding;
        public event BindingHandler AfterBinding;
        public event BindingHandler BeforeUnbinding;
        public event BindingHandler AfterUnbinding;

        # endregion

        protected new void BuildFromConfiguration()
        {
            base.Build();

            if (Configuration == null)
                return;

            # region Creating child controls
            
            Table table = new Table();            
            Controls.Add(table);
            table.Width = Configuration.Width;
            table.Style.Add("display","inline");
            
            TableRow headerRow = null;
            TableCell headerCell = null;

            if (Configuration.HeaderConfiguration != null)
            {
                headerRow = new TableRow();
                table.Controls.Add(headerRow);
                
                headerCell = new TableCell();
                headerRow.Controls.Add(headerCell);
                
                Label header = new Label(Configuration.HeaderConfiguration);
                headerCell.Controls.Add(header);              
            }
            
            TableRow buttonsRow = null;

            if (Configuration.SelectButtonsPosition != ListButtonPosition.None)
            {    
                TableCell buttonsCell = null;
                
                if (Configuration.SelectButtonsPosition == ListButtonPosition.TopRight ||
                    Configuration.SelectButtonsPosition == ListButtonPosition.TopLeft)
                {
                    if (headerRow != null)
                    {
                        buttonsRow = headerRow; 
                        
                        if (Configuration.SelectButtonsPosition == ListButtonPosition.TopRight)
                        {
                            buttonsCell = new TableCell();
                            buttonsRow.Controls.Add(buttonsCell);
                        }
                        else
                        {
                            buttonsCell = headerCell;
                            buttonsCell.Controls.Add(new System.Web.UI.LiteralControl("&nbsp;&nbsp;"));
                        }
                    }
                    else
                    {
                        buttonsRow = new TableRow();
                        table.Controls.Add(buttonsRow);

                        buttonsCell = new TableCell();
                        buttonsRow.Controls.Add(buttonsCell);
                    }
                }
                else
                {
                    buttonsRow = new TableRow();

                    buttonsCell = new TableCell();
                    buttonsRow.Controls.Add(buttonsCell);
                }

                switch (Configuration.SelectButtonsPosition)
                {
                    case ListButtonPosition.TopRight:
                    case ListButtonPosition.BottomRight:
                        {
                            buttonsCell.Attributes.Add("align", "right");                            
                            break;
                        }
                    case ListButtonPosition.TopLeft:
                    case ListButtonPosition.BottomLeft:
                        {
                            buttonsCell.Attributes.Add("align", "left");                            
                            break;
                        }
                    //case ListButtonPosition.TopCenter:
                    //case ListButtonPosition.BottomCenter:
                    //    {
                    //        align = "center";
                    //        break;
                    //    }
                    default:
                        {
                            throw new Exception("Unknown select buttons position: " + Configuration.SelectButtonsPosition);
                        }
                }

                selectAll.Visible = true;
                selectAll.Text = 
                    String.Format("<a href=\"#\" class=\"listSelectButton\" onclick=\"{0}.markAll();\">Select All</a>",
                    Configuration.ClientVariable);

                unselectAll.Visible = true;                
                unselectAll.Text =
                    String.Format(
                        "<a href=\"#\" class=\"listSelectButton\" onclick=\"{0}.unmarkAll();\">Unselect All</a>",
                        Configuration.ClientVariable);


                buttonsCell.Controls.Add(new System.Web.UI.LiteralControl("<nobr>"));
                buttonsCell.Controls.Add(selectAll);
                buttonsCell.Controls.Add(new System.Web.UI.LiteralControl("&nbsp;&nbsp;"));
                buttonsCell.Controls.Add(unselectAll);
                buttonsCell.Controls.Add(new System.Web.UI.LiteralControl("</nobr>"));
            }
            
            TableRow divRow = new TableRow();            
            table.Controls.Add(divRow);
            
            TableCell divCell = new TableCell();
            divRow.Controls.Add(divCell);  
            
            if (Configuration.SelectButtonsPosition == ListButtonPosition.TopRight)
            {
                divCell.ColumnSpan = 2;
            }

            WebControl div = new WebControl(HtmlTextWriterTag.Div);
            divCell.Controls.Add(div);
            div.Style.Add("width", Configuration.Width.ToString());
            div.Style.Add("height", Configuration.Height.ToString());
            //div.Style.Add("overflow-y", "scroll");
            div.Style.Add("overflow", "auto");            
            div.Style.Add("border", "solid 1px black");
            div.Controls.Add(checkListBox);

            checkListBox.Attributes.Add("RepeatLayout", "Flow");

            if (Configuration.SelectButtonsPosition != ListButtonPosition.None &&
                (Configuration.SelectButtonsPosition == ListButtonPosition.BottomRight ||
                Configuration.SelectButtonsPosition == ListButtonPosition.BottomLeft))
            {
                table.Controls.Add(buttonsRow);
            }

            # endregion

            Controller = Configuration.Controller != null ? (IMultiSelectListController)Configuration.Controller.Clone() : null;
        }

        void Controller_OnControlChanged(Control control)
        {
            if (control != this)
                Controller = null;
        }

        protected override void OnInit(EventArgs e)
        {
            if (configuration == null)
            {
                configuration = (IConfiguration)SpringContextFactory.GetContext().GetObject(configurationId);
                BuildFromConfiguration();
            }

            ControlUtil.SetupClientAttributes(this, configuration);
            binder = new DataBinder(this, configuration, ExecutionContext.GetCurrent(ClientID));
            base.OnInit(e);
        }

        public override void OnDataLoad()
        {
            IDictionary executionContext = ExecutionContext.GetCurrent(ClientID);
            ControlUtil.ExecuteOnDataLoad(executionContext, Context, Configuration, this.ClientID);
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            IExecutionContext executionContext = ExecutionContext.GetCurrent(ClientID);
            Unbind();
            ControlUtil.ExecuteOnLoad(executionContext, Context, Configuration, this.ClientID);

            if (Configuration.VisibleBindPath != null)
            {
                this.Visible = true; // To reach the OnPreRender method and analyze visibility in the Bind method
            }
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            IDictionary executionContext = ExecutionContext.GetCurrent(ClientID);
            ControlUtil.ExecuteOnPreRender(executionContext, Context, Configuration, this.ClientID);

            Bind();

            //if (ClientScriptingEnabled)
            //{
            //    //				EnableClientScripting();
            //    DeclareScriptVariable();
            //}
            EnableClientScripting();
        }

        private void EnableClientScripting()
        {
            ControlUtil.EnsureIdAttribute(this);
            JavascriptController jsController = JavascriptController.Current;

            jsController.DeclareClass(Configuration.JavascriptClass);
            jsController.DeclareObject(ClientVariable, Configuration.JavascriptClass,
                                       JavascriptUtil.EncloseWithQuotes(ClientID),
                                       JavascriptUtil.GetElementById(checkListBox.ClientID),
                                       JavascriptUtil.ToScriptObject(this.Enabled));
        }

        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            RenderScriptAttributes(writer);
        }

        private void BindDataSource()
        {
            # region Setting Data Fields

            object dataTextField = Configuration.DataTextField;

            if (String.IsNullOrEmpty(Configuration.DataTextField) && !binder.GetPropertyValue("DataTextField", out dataTextField))
            {
                dataTextField = "Text";
            }

            object dataValueField = Configuration.DataValueField;

            if (String.IsNullOrEmpty(Configuration.DataValueField) && !binder.GetPropertyValue("DataValueField", out dataValueField))
            {
                dataValueField = "Value";
            }

            DataTextField = dataTextField.ToString();
            DataValueField = dataValueField.ToString();

            # endregion                       

            /* Neither of sort order, sort expression, virtual item count and etc. must save by grid instance,
             * all of these were replaced to the IFilterState and IGridController */
            if (controller != null)
            {
                Controller.LoadOrRefresh();
            }
            else
            {
                object dataSource;                
                
                if (!binder.GetPropertyValue("DataSource", out dataSource))
                {
                    return; //No source sould be binded;
                }

                DataSource = dataSource;

                DataBind();                
            }

            # region Selecting Items
            
            object selectedItems;

            if ((controller == null || String.IsNullOrEmpty(controller.SelectedItemsPath)) && 
                binder.GetPropertyValue("SelectedItems", out selectedItems) && selectedItems != null)
            {
                ICollection values = null;

                if (selectedItems is IDictionary)
                    values = (selectedItems as IDictionary).Keys;
                else
                    if (selectedItems is ICollection)
                        values = (selectedItems as ICollection);
                    else
                        if (selectedItems is StringDictionary)
                            values = (selectedItems as StringDictionary).Keys;
                        else
                            if (selectedItems is ListItemCollection)
                            {
                                values = new ArrayList();

                                foreach (ListItem item in (selectedItems as ListItemCollection))
                                {
                                    (values as IList).Add(item.Value);
                                }
                            }

                if (values == null)
                    throw new Exception("Unknown selected items type");

                foreach (object value in values)
                {
                    if (value == null)
                        throw new Exception("Selected item value can't be null");

                    ListItem item = Items.FindByValue((value is ListItem) ? (value as ListItem).Value : value.ToString());

                    if (item != null)
                        item.Selected = true;
                }
            }

            # endregion
        }

        public override void DataBind()
        {
            checkListBox.DataBind();
        }

        protected override void Bind()
        {
            if (BeforeBinding != null)
                BeforeBinding(this);
            
            Visible = configuration.Visible;

            BindDataSource();

            binder.Bind(new string[] { "Enabled", "Visible" });

            if (controller == null || String.IsNullOrEmpty(controller.SelectedItemsPath))
            {
                binder.Bind("SelectedIndex");
                binder.Bind("SelectedValue");
            }

            Enabled = Enabled && configuration.IsEnabledForPrincipal();
            Visible = Visible && configuration.IsVisibleForPrincipal();
                       
            if (!Enabled)
            {
                foreach (ListItem l in Items)
                {
                    l.Enabled = false;
                 
                }
                
                selectAll.Visible = false;
                unselectAll.Visible = false;                
                
                Enabled = true;
            }

            if (AfterBinding != null)
                AfterBinding(this);
        }

        protected override void Unbind()
        {
            if (BeforeUnbinding != null)
                BeforeUnbinding(this);
            
            binder.Unbind(new string[] { "Enabled", "Visible", "SelectedIndex", "SelectedText", "SelectedValue", "DataSource", "DataValueField", "DataTextField" });

            //IList selectedItems = new ArrayList();
            IDictionary selectedItems = new OrderedDictionary();

            foreach (ListItem item in Items)
            {
                if (item.Selected)
                {
                    //selectedItems.Add(item);
                    selectedItems.Add(item.Value, item.Text);
                }
            }

            binder.SetPropertyValue("SelectedItems", selectedItems);  

            if (AfterUnbinding != null)
                AfterUnbinding(this);
        }        
    }
}
